<template>
  <div class="view">
    <el-card class="view-card">
      <template #header>
        <div class="header">
          <span class="title">NFT Creator</span>

          <el-button-group>
            <Read ref="readRef" />
            <BaseSetting ref="baseRef" />
            <ItemsSetting ref="itemRef" />
            <Help />
          </el-button-group>
        </div>
      </template>

      <div class="content">
        <div class="creator">
          <canvas id="cvs"></canvas>
          <div class="help">
            <div class="statuses">
              <span>是否运算中：{{storeByCreator.state.calcloading ? '是' : '否'}}</span>
              <span>是否组选中：{{storeByCreator.state.groupSelectLoading ? '是' : '否'}}</span>
              <span>是否暂停运算：{{storeByCreator.state.calcPause ? '是' : '否'}}</span>
            </div>
            <li>确保根目录中【assets】下有可用图片组文件；</li>
            <li @click="handleOpenBase">修改【基础配置】中的【图片默认最大生成次数】；确认后点击【保存】</li>
            <li @click="handleRead">点击【读取】按钮，读取文件并生成默认配置；</li>
            <li @click="handleOpenItem">修改【元素配置】中，组的层级及关联管理；元素的name；确认后点击【保存】</li>
            <li>
              <span @click="handleCalc">进行生成之前的计算</span>
              <div>
                <ElButton type="danger" @click="() => storeByCreator.dispatch('selectPause')">暂停</ElButton>
                <ElButton type="success" @click="() => storeByCreator.dispatch('selectContinue')">继续</ElButton>
              </div>
            </li>
            <li @click="handleOpenBase">修改【基础配置】中的【设计稿宽度】及【设计稿高度】；确认后点击【保存】</li>
            <li>
              <span @click="handleCreate">生成并导出</span>
              <div class="input-group">
                <ElInput class="input" v-model="limitMin" placeholder="生成NFT数据始" />
                <ElInput class="input" v-model="limitMax" :placeholder="`生成NFT数据止，最大为：${storeByCreator.state.prefabImagePool.length}`" />
              </div>
            </li>

            <div class="tip">
              <p v-for="it in storeByCreator.state.calcPrefabTip" :key="it">{{ it }}</p>
            </div>
          </div>
        </div>
      </div>
    </el-card>
  </div>
</template>

<script lang="ts" setup>
import Help from "./templates/Help.vue";
import Read from "./templates/Read.vue";
import ItemsSetting from "./templates/ItemsSetting.vue";
import BaseSetting from "./templates/BaseSetting.vue";
import { useNFTCreatorStore } from "@/store/NFTCreator.store";
import { configStore, useConfigStore } from "@/store/config.store";
import { onMounted, ref } from 'vue'
import JSZip from 'jszip';
import { saveAs } from 'file-saver'
import utils from "@/utils";
import { ElMessage } from "element-plus";

const storeByConfig = useConfigStore();
const storeByCreator = useNFTCreatorStore(storeByConfig);
const readRef = ref<InstanceType<typeof Read>>();
const baseRef = ref<InstanceType<typeof BaseSetting>>();
const itemRef = ref<InstanceType<typeof ItemsSetting>>();
const limitMin = ref();
const limitMax = ref();
let cvs: HTMLCanvasElement;
let ctx: CanvasRenderingContext2D;

const handleRead = () => readRef.value?.read();
const handleOpenBase = () => baseRef.value?.open();
const handleOpenItem = () => itemRef.value?.open();
const loadImg = (url: string, delay: number = 0): Promise<HTMLImageElement> => new Promise((resolve, reject) => {
  const img = new Image()
  // img.crossOrigin = 'Anonymous'
  img.setAttribute('crossOrigin', 'anonymous')
  img.onload = () => {
    setTimeout(() => {
      resolve(img)
    }, delay);
  }

  img.src = `${url}?tmp=${Date.now()}`
});
const handleCalc = () => storeByCreator.dispatch('CalcItems');
const handleCreate = async () => {
  const {designWidth: width, designHeight: height, baseUrl} = storeByConfig.state.currentBaseConfig

  cvs.width = width;
  cvs.height = height;

  let zip: JSZip = new JSZip()
  let zipSize = 0

  const save = async () => {
    const content = await zip.generateAsync({ type: 'blob' })
    saveAs(content, `图片-${Date.now()}.zip`);
    console.log(`导出一个文件，大小：${zipSize / 1024 / 1024}MB`);

    await utils.sleep(1000)

    zip = new JSZip()
    zipSize = 0
  }

  if (!limitMin.value || !limitMax.value) return ElMessage.error('请填写数据限制')

  const paths = storeByCreator.state.prefabImagePool.slice(limitMin.value, limitMax.value)
  if (!paths || !paths.length) return ElMessage.error('请先生成数据！')

  for (const pathIdx in paths) {
    const path = paths[pathIdx]
    ctx.clearRect(0, 0, width, height)

    const idx = Number(pathIdx) + 1
    const option: Record<string, string> = {}

    for (const itemId of path) {
      const curItem = storeByConfig.state.currentItems.find(k => k.id === itemId)
      const group = storeByConfig.state.currentGroup.find(k => k.id === curItem?.gid)
      storeByCreator.commit('log', `正在绘制第${idx}张图片，部位：${group?.name}`)
      console.log(`正在绘制第${idx}张图片，部位：${group?.name}`);

      if (curItem) {
        if (group?.isExportJson) {
          const name = curItem.name.split('.')
          option[group?.name || curItem.gName] = name.slice(0, name.length - 1).join('')
        }
        const curItemUrl = `${baseUrl}${curItem.url}`

        const img = await loadImg(curItemUrl)

        ctx.drawImage(img, 0, 0, width, height)
      }
    }

    const imgUrl = cvs.toDataURL()
    const imgRes = imgUrl.replace('data:image/png;base64,', '')
    zip.file(`图片${idx}.png`, imgRes, { base64: true })
    const optionRes = JSON.stringify(option, null, 2)
    zip.file(`图片${idx}参数.json`, optionRes)
    zipSize += imgRes.length + optionRes.length

    if (zipSize > 1024 * 1024 * 300 || Number(pathIdx) === paths.length - 1) {
      await save()
    }
  }
};
const initCvs = () => {
  const {designWidth: width, designHeight: height} = storeByConfig.state.currentBaseConfig
  cvs = document.querySelector('#cvs') as HTMLCanvasElement
  cvs.width = width
  cvs.height = height

  ctx = cvs.getContext('2d') as CanvasRenderingContext2D;
};

onMounted(initCvs);
</script>

<style lang="less" scoped>
@import url('../assets/less/mixin.less');
.view{padding:12px; height:100%;
  &-card{height:100%}
}
.header{.flex(space-between); .title(20px);}
#cvs{width:500px; height:500px; border:1px solid #000;}
.content{.flex-col();
  .tip{color:red; font-size:16px; font-weight:bold; height:2em;
    width:100%; text-align:left;
  }
}
.creator{width:100%; .flex(space-between;flex-start);
  .help{list-style:decimal; width:40%; padding-left:15px;
    li{cursor:pointer; margin-bottom:7px; letter-spacing:1px;
      color:#000; font-weight:300; transition:.3s;
      &:hover{color:red; font-weight:600;}
    }
  }
}
.input-group{.flex(space-between)}
.input{width:48%;}
.statuses{margin-bottom:12px; font-size:18px;
  span{margin-right:10px; font-weight:bold; color:#e91e63;
    display:block;
  }
}
</style>
